use core::str;
use uuid::Uuid;

pub trait Draw {
    fn draw(&self);
}

pub struct Screen {
    pub components: Vec<Box<dyn Draw>>,
}

impl Screen{
    pub fn run(&self) {
        for ele in self.components.iter() {
            ele.draw();
        }
    }
}

pub struct Button {
    pub width: u32,
    pub height: u32,
    pub label: String,
}

impl Draw for Button {
    fn draw(&self) {
        println!("Button draw");
    }
}

struct SelectBox {
    pub width: u32,
    pub height: u32,
    pub options: Vec<String>,
}

impl Draw for SelectBox {
    fn draw(&self) {
        println!("SelectBox draw");
    }
}

pub fn exe() {
    let screen = Screen {
        components: vec![
            Box::new(SelectBox {
                width: 75,
                height: 10,
                options: vec![
                    String::from("Yes"),
                    String::from("Maybe"),
                    String::from("No"),
                ],
            }),
            Box::new(Button {
                width: 50,
                height: 10,
                label: String::from("OK"),
            }),
        ],
    };

    screen.run();
}


// 模拟博文发布


trait State {
    fn request_review(self:Box<Self>) -> Box<dyn State>;
    fn approve(self:Box<Self>) -> Box<dyn State>;
    fn content<'a>(&self,post:&'a Post)-> &'a str {
        ""
    }
}

/**
 * 草稿状态
 */
struct Draft{}

impl State for  Draft {
    fn request_review(self:Box<Self>) -> Box<dyn State> {
        Box::new(PendingReview{})
    }

    fn approve(self:Box<Self>) -> Box<dyn State> {
        self
    }
}

/**
 * 审核状态
 */
struct PendingReview{}

impl State for PendingReview {
    fn request_review(self:Box<Self>) -> Box<dyn State> {
        self
    }
    fn approve(self:Box<Self>) -> Box<dyn State> {
        Box::new(Published{})
    }
}

/**
 * 发布状态
 */
struct Published{}

impl State for Published {
    fn approve(self:Box<Self>) -> Box<dyn State> {
        self
    }
    fn request_review(self:Box<Self>) -> Box<dyn State> {
        self
    }

    fn content<'a>(&self,post:&'a Post)-> &'a str {
        &post.content
    }
}

pub struct Post{
    state:Option<Box<dyn State>>,
    content:String,
}

impl Post {
    pub fn new() -> Post{
        Post{
            state:Some(Box::new(Draft{})),
            content:String::new(),
        }
    }

    pub fn add_test(&mut self,text:&str) {
        self.content.push_str(text);
    }

    pub fn content(&self)->&str {
        self.state.as_ref().unwrap().content(self)
    }

    /**
     * 审核
     */
    pub fn request_review(&mut self){
        if let Some(s) = self.state.take() {
            self.state  = Some(s.request_review())
        }
    }

    /**
     * 批准
     */
    pub fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
}

pub fn blob_exe(){
    let mut post = Post::new();
    post.add_test("这个是一个测试");
    post.request_review();
    post.approve();
    println!("post:{}",post.content())
}



trait PayStrategy {
    fn pay(&self,pay:&Pay)->String;

    fn cancel(&self,pay:&Pay);

    fn common(&self){
        println!("默认方法")
    }
}

struct Alipay{}
impl PayStrategy for Alipay {
    fn cancel(&self,pay:&Pay) {
        println!("支付宝取消支付,业务订单号:{},支付订单号:{}",pay.biz_order_id,pay.pay_order_id)
    }
    fn pay(&self,pay:&Pay)->String {
        println!("支付宝支付,金额:{},业务订单号:{}",pay.amount,pay.biz_order_id);
        Uuid::new_v4().to_string()
    }
}
struct WechatPay{}
impl PayStrategy for WechatPay {
    fn cancel(&self,pay:&Pay) {
        println!("微信支付取消支付,业务订单号:{},支付订单号:{}",pay.biz_order_id,pay.pay_order_id)
    }
    fn pay(&self,pay:&Pay)->String {
        println!("微信支付,金额:{}",pay.amount);
        let uuid = Uuid::new_v4();
        println!("支付成功,订单号:{}",&uuid);
        uuid.to_string()

    }
}

pub struct Pay{
    pay_strategy:Box<dyn PayStrategy>,
    pub amount:f64,
    pub biz_order_id:String,
    pub pay_order_id:String,
}

impl Pay{

    fn new(strategy:Box<dyn PayStrategy>,amount:f64,biz_order_id:String)->Pay {
        Pay{
            pay_strategy:strategy,
            amount,
            biz_order_id,
            pay_order_id:String::new(),
        }
    }
    fn common(&self) {
        self.pay_strategy.common();
    }

    fn pay(&self)->String {
        self.pay_strategy.pay(&self)
    }

    fn cancel(&self){
        self.pay_strategy.cancel(&self)
    }
}

enum PayType {
    Alipay,
    WechatPay,
}
impl PayType {
    fn new(self,amount:f64,biz_order_id:String) -> Pay{
        match self {
            PayType::Alipay => Pay::new(Box::new(Alipay{}),amount,biz_order_id),
            PayType::WechatPay => Pay::new(Box::new(WechatPay{}),amount,biz_order_id),
        }
    }
}

pub fn pay_exe(){
    let mut pay = PayType::WechatPay.new(1688.99, Uuid::new_v4().to_string());
    let pay_id = pay.pay();
    println!("pay_id: {}", pay_id);
    pay.pay_order_id = pay_id;
    pay.common();
    pay.cancel();
}